package com.netty.example.nio;

import java.io.IOException;
import java.lang.reflect.Member;
import java.lang.reflect.WildcardType;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

public class NIOServer {

    private static final Map<String, SocketChannel> clientMap = new HashMap();

    public static void main(String[] args) {
        try {
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            ServerSocket serverSocket = serverSocketChannel.socket();
            serverSocket.bind(new InetSocketAddress(8899));
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            System.out.println("serverSocketChannel register");
            while (true) {
                int numbers = selector.select();
                SocketChannel socketChannel;
                System.out.println("numbers: " + numbers);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                for (SelectionKey selectionKey : selectionKeys) {
                    if (selectionKey.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                        socketChannel = ssc.accept();
                        socketChannel.configureBlocking(false);
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        String key = "[" + UUID.randomUUID() + "]";
                        clientMap.put(key, socketChannel);
                        System.out.println("client connnect key: " + key + ", socketChannel: " + socketChannel);
                    } else if (selectionKey.isReadable()) {
                        socketChannel = (SocketChannel) selectionKey.channel();
                        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                        String message = null;
                        while (true) {
                            byteBuffer.clear();
                            try {
                                int count = socketChannel.read(byteBuffer);
                                if (count == 0) break;
                                if (count < 0) {
                                    System.out.println("socketChannel close: " + socketChannel);
                                    socketChannel.close();
                                    break;
                                }
                                byteBuffer.flip();
                                Charset charset = Charset.forName("utf-8");
                                message = String.valueOf(charset.decode(byteBuffer).array());
                                System.out.println(socketChannel + ": " + message);
                            } catch (ClosedChannelException e) {
                            } catch (IOException e) {
                            }
                        }
                        String senderKey = null;
                        if (message != null) {
                            for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
                                if (socketChannel == entry.getValue()) {
                                    senderKey = entry.getKey();
                                    break;
                                }
                            }
                            for (Map.Entry<String, SocketChannel> entry : clientMap.entrySet()) {
                                if (socketChannel != entry.getValue()) {
                                    ByteBuffer writerBuffer = ByteBuffer.allocate(1024);
                                    writerBuffer.put((senderKey + ": " + message).getBytes());
                                    writerBuffer.flip();
                                    entry.getValue().write(writerBuffer);
                                }
                            }
                        }
                    }
                }
                selectionKeys.clear();
            }
        } catch (IOException e) {
        }
    }
}
